# -*- coding: utf-8 -*-
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, Image, Spacer, Table, TableStyle, HRFlowable
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import inch
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from PIL import Image as PILImage, ImageDraw, UnidentifiedImageError
import base64
import datetime
import hashlib
import hmac
import json
import ssl
import websocket
import _thread as thread
from datetime import datetime
from time import mktime
from urllib.parse import urlparse
from urllib.parse import urlencode
from wsgiref.handlers import format_date_time
from combine_chat import Combine_Chat
from reportlab.lib.enums import TA_CENTER  # Import the constants for alignment
answer = ""

appid = "d3fb4c44"
api_secret = "OGNjNmY5N2M0NDhmZDQ4YzIxOTc2ZjUz"
api_key = "85311692ef36b5181251a367868fe9fe"
imageunderstanding_url = "wss://spark-api.cn-huabei-1.xf-yun.com/v2.1/image"


class Ws_Param(object):
    # 初始化
    def __init__(self, APPID, APIKey, APISecret, imageunderstanding_url):
        self.APPID = APPID
        self.APIKey = APIKey
        self.APISecret = APISecret
        self.host = urlparse(imageunderstanding_url).netloc
        self.path = urlparse(imageunderstanding_url).path
        self.ImageUnderstanding_url = imageunderstanding_url

    # 生成url
    def create_url(self):
        # 生成RFC1123格式的时间戳
        now = datetime.now()
        date = format_date_time(mktime(now.timetuple()))

        # 拼接字符串
        signature_origin = "host: " + self.host + "\n"
        signature_origin += "date: " + date + "\n"
        signature_origin += "GET " + self.path + " HTTP/1.1"

        # 进行hmac-sha256进行加密
        signature_sha = hmac.new(
            self.APISecret.encode("utf-8"),
            signature_origin.encode("utf-8"),
            digestmod=hashlib.sha256,
        ).digest()

        signature_sha_base64 = base64.b64encode(signature_sha).decode(encoding="utf-8")

        authorization_origin = f'api_key="{self.APIKey}", algorithm="hmac-sha256", headers="host date request-line", signature="{signature_sha_base64}"'

        authorization = base64.b64encode(authorization_origin.encode("utf-8")).decode(
            encoding="utf-8"
        )

        # 将请求的鉴权参数组合为字典
        v = {"authorization": authorization, "date": date, "host": self.host}
        # 拼接鉴权参数，生成url
        url = self.ImageUnderstanding_url + "?" + urlencode(v)
        # print(url)
        # 此处打印出建立连接时候的url,参考本demo的时候可取消上方打印的注释，比对相同参数时生成的url与自己代码生成的url是否一致
        return url


# 收到websocket错误的处理
def on_error(ws, error):
    print("### error:", error)


# 收到websocket关闭的处理
def on_close(ws, one, two):
    print(" ")


# 收到websocket连接建立的处理
def on_open(ws):
    thread.start_new_thread(run, (ws,))


def run(ws, *args):
    data = json.dumps(gen_params(appid=ws.appid, question=ws.question))
    ws.send(data)


# 收到websocket消息的处理
def on_message(ws, message):
    # print(message)
    data = json.loads(message)
    code = data["header"]["code"]
    if code != 0:
        print(f"请求错误: {code}, {data}")
        ws.close()
    else:
        choices = data["payload"]["choices"]
        status = choices["status"]
        content = choices["text"][0]["content"]
        #print(content, end="")
        global answer
        answer += content
        # print(1)
        if status == 2:
            ws.close()

        with open("/home/xinan-works/analyze_res.txt",'w') as file:
            file.write(answer)


def gen_params(appid, question):

    data = {
        "header": {"app_id": appid},
        "parameter": {
            "chat": {
                "domain": "image",
                "temperature": 0.5,
                "top_k": 4,
                "max_tokens": 2028,
                "auditing": "default",
            }
        },
        "payload": {"message": {"text": question}},
    }

    return data


def main(appid, api_key, api_secret, imageunderstanding_url, question):

    wsParam = Ws_Param(appid, api_key, api_secret, imageunderstanding_url)
    websocket.enableTrace(False)
    wsUrl = wsParam.create_url()
    ws = websocket.WebSocketApp(
        wsUrl,
        on_message=on_message,
        on_error=on_error,
        on_close=on_close,
        on_open=on_open,
    )
    ws.appid = appid
    # ws.imagedata = imagedata
    ws.question = question
    ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})


def getText(role, imagepath, content):
    imagedata = open(imagepath, "rb").read()

    text = [
        {
            "role": role,
            "content": str(base64.b64encode(imagedata), "utf-8"),
            "content_type": "image",
        },
        {
            "role": role,
            "content": content,
            "content_type": "text",
        },
    ]

    return text


def getlength(text):
    length = 0
    for content in text:
        temp = content["content"]
        leng = len(temp)
        length += leng
    return length


def checklen(text):
    while getlength(text[1:]) > 8000:
        del text[1]
        print("d", end="")
    return text

def add_title(story, title_text, font_size=18):
    styles = getSampleStyleSheet()
    title_style = ParagraphStyle(
        name='Title',
        parent=styles['Title'],
        fontSize=font_size,
        fontName='SimSun',
        spaceAfter=5
    )
    title = Paragraph(title_text, title_style)
    story.append(title)

def add_text(story, text_content, font_size=12):
    styles = getSampleStyleSheet()
    normal_style = ParagraphStyle(
    name='Normal',
    parent=styles['Normal'],
    fontName='SimSun',  # Set the font to SimSun
    fontSize=font_size,  # Set the desired font size
    spaceAfter=5,
    alignment=TA_CENTER  # Set text alignment to center
    )
    normal_text = Paragraph(text_content, normal_style)
    story.append(normal_text)

def round_image_corners(image_path, radius):
    try:
        img = PILImage.open(image_path).convert("RGBA")
    except UnidentifiedImageError:
        print(f"Error: Cannot identify image file {image_path}")
        return None
    circle = PILImage.new('L', (radius * 2, radius * 2), 0)
    draw = ImageDraw.Draw(circle)
    draw.ellipse((0, 0, radius * 2, radius * 2), fill=255)
    alpha = PILImage.new('L', img.size, 255)
    w, h = img.size
    alpha.paste(circle.crop((0, 0, radius, radius)), (0, 0))
    alpha.paste(circle.crop((0, radius, radius, radius * 2)), (0, h - radius))
    alpha.paste(circle.crop((radius, 0, radius * 2, radius)), (w - radius, 0))
    alpha.paste(circle.crop((radius, radius, radius * 2, radius * 2)), (w - radius, h - radius))
    img.putalpha(alpha)
    return img

def add_image_and_text(story, img_path, img_width, img_height, text_content, font_size=12, radius=20):
    styles = getSampleStyleSheet()
    normal_style = ParagraphStyle(
    name='Normal',
    parent=styles['Normal'],
    fontName='SimSun',  # 设置字体为宋体
    fontSize=font_size,  # 设置字号大小
    spaceAfter=10,  # 设置段落后间距
    leftIndent=24,  # 设置段首缩进
    leading=16  # 设置行间距，例如设置为字号的 1.2 倍
)

    rounded_img = round_image_corners(img_path, radius)
    if rounded_img:
        rounded_img_path = img_path.replace('.png', '_rounded.png').replace('.jpg', '_rounded.png')
        rounded_img.save(rounded_img_path, format="PNG")

        img = Image(rounded_img_path, img_width, img_height)
        img.drawHeight = img_height
        img.drawWidth = img_width
        story.append(Spacer(1, 0.3 * inch))  # Spacer before table
        text = Paragraph(text_content, normal_style)
        space = ''
        data = [[img,space ,text]]
        table = Table(data, colWidths=[img_width, None])

        table.setStyle(TableStyle([
            ('VALIGN', (0, 0), (-1, -1), 'TOP')
        ]))

        story.append(Spacer(1, 0.3 * inch))  # Spacer before table
        story.append(table)
        story.append(Spacer(1, 0.3 * inch))  # Spacer after table


def generate_pdf(output_filename, paragraph1, paragraph2, paragraph3,paragraph4, paragraph5,img_paths):
    doc = SimpleDocTemplate(output_filename, pagesize=letter)
    story = []

    add_title(story, "灵眸识幻", font_size=18)

    add_text_content = """
    基于指纹特征的图像特征检测平台
    """
    add_text(story, add_text_content, font_size=14)  # Set desired font size

    img_width = 2 * inch
    img_height = 2 * inch

    for i, (paragraph, img_path) in enumerate(zip([paragraph1, paragraph2, paragraph3,paragraph4,paragraph5], img_paths)):
        add_image_and_text(story, img_path, img_width, img_height, f"{paragraph}", font_size=14)  # Set desired font size
        add_title(story, "-----------------------------------------------------------------", font_size=14)
    answer = ""

    #添加最后的拼接总结
    Combine_Chat()


    Combine_res = ''
    with open("/home/xinan-works/Combine_chat_res.txt",'r') as file:
        Combine_res += file.read()
    add_text(story,Combine_res, font_size=14)  # Set desired font size
    
    doc.build(story)

def generate():
    with open("/home/xinan-works/noiser_res_num.txt",'r') as file:
        noise_res = float(file.read())
    if noise_res>0.4:
        noise_ = "被修改的可能性较高"
    else:
        noise_ ="被修改的可能性较低"
    pdfmetrics.registerFont(TTFont('SimSun', 'simsun.ttc'))  # Register SimSun font
    paragraph1 = "  噪声方差提取结果:将图像分块进行噪声方差提取后聚类分析如果聚类中心点数值差大于阈值，则存在“覆盖篡改”的可能性较高。"+noise_
    paragraph2 = "  SIFT特征点提取匹配结果:提取SIFT图像特征点，对于相似的特征点内的特征点进行-一-映射:如果图像出现了连线，则至少说明存在相似区域，“复制-粘贴”类图像篡改的可能性较高"
    paragraph3 = "  误差水平分析结果:原图和有损压缩后的图像进行差异提取与增强。如果图像中出现少量差异特征亮点，属于正常范围;如果图像中出现大量差异特征亮点，则说明“像素变换相关的篡改”的可能性较高。"
    paragraph4 = "  噪声指纹提取结果:噪声指纹差异区域以灰色表征，颜色越浓表征差异越强，如果图像是经过伪造或篡改的，则极有可能是被篡改区域。噪声指纹提取结果附带一个归一化的改置信度值，数值越大，越有可能是经过伪造的:0.7以上几平可以确定是伪造的，0.4~0.7有一定的可能是伪造的，0.4以下伪造的可能性较低"
    paragraph5 = "  lsb图像通道低位提取结果:对图像颜色通道的低位进行提取成灰度图，一般来说图像比较嘈杂无规律，jpeg格式的图片因为压缩所以会导致一些块状区域出现"
    with open("/home/xinan-works/noiser_res_num.txt",'r') as file:
        noise_res = file.read()
    #触发噪声方差分析
    raw = f"""
    注意你是一个严谨的学者
请你对以下问题做出判断，如果{noise_res}大于0.4，则存在“覆盖篡改”的可能性较高,否则较小。
请以以下格式回答：_____(较大可能/可能较小 选取其一)，加粗结果部分
最后要求，输出的全段话不包括下划线和括号
"""
    answer = ""
    question = checklen(getText("user", "/home/xinan-works/res/noise_res.jpg", raw))

    main(appid, api_key, api_secret, imageunderstanding_url, question)
    #将噪声方差的结果返回给res
    with open ('/home/xinan-works/analyze_res.txt','r') as file:
        data1 = file.read()
    paragraph1_extend = paragraph1+"\n"+"判断的结果是:"+data1
    #触发SIFT分析
    raw = f"""
    注意你是一个严谨的学者，你知道复制-粘贴类型篡改检测的方法可以通过SIFT特征点提取匹配。提取SIFT图像特征点，对于相似的特征点内的特征点进行-一-映射；如果图像出现了连线，则至少说明存在相似区域，“复制-粘贴”类图像篡改的可能性较高，不合理；反之，按照出现连线的多少给出合理性
作为图像伪造篡改检测领域的专家，你现在面对一个SIFT特征点相似映射图像进行分析。注意,你需要严格以下格式进行回答：“复制-粘贴”类型篡改的可能性（填 较低/较高/很高)选取其一，其判断依据是什么
最后要求，输出的全段话不包括下划线和括号
    """
    answer = ""
    question = checklen(getText("user", "/home/xinan-works/res/forgery_result.jpg", raw))

    main(appid, api_key, api_secret, imageunderstanding_url, question)
    #将噪声方差的结果返回给res
    with open ('/home/xinan-works/analyze_res.txt','r') as file:
        data2 = file.read()
    paragraph2_extend = paragraph2+"\n"+"判断的结果是:"+data2

    # 误差水平分析
    raw="""
        误差水平分析结果：原图和有损压缩后的图像进行差异提取与增强。如果图像中出现少量差异特征亮点，属于正常范围；如果图像中出现大量差异特征亮点，则说明“像素变换相关的篡改”的可能性较高。
    作为图像伪造篡改检测领域的专家，你现在面对一个误差水平差异提取的图像进行分析。注意，你需要严格以以下格式进行回答：所给图像中差异特征亮点范围(较大/较小)选取其一，数量多少(较多/较少)选取其一，差异是否(明显/不显著)选取其一，伪造篡改的可能性(较小/较大)选取其一
    最后要求，输出的全段话不包括下划线和括号
    """
    answer=""
    question=checklen(getText("user",'/home/xinan-works/res/ela/difference_scaled.png',raw))
    main(appid, api_key, api_secret, imageunderstanding_url, question)
    with open ('/home/xinan-works/analyze_res.txt','r') as file:
        data3 = file.read()
    paragraph3_extend = paragraph3+"\n"+"判断的结果是:"+data3

    # 图像噪声指纹分析
    with open("/home/xinan-works/truefor_num.txt",'r') as file:
        truefor_num = file.read()
    raw=f"""
    噪声指纹提取结果:噪声指纹差异区域以灰色表征，颜色越浓表征差异越强，如果图像是经过伪造或篡改的，则极有可能是被篡改区域。噪声指纹提取结果附带一个归一化的改置信度值，数值越大，越有可能是经过伪造的:0.7以上几平可以确定是伪造的，0.4~0.7有一定的可能是伪造的，0.4以下伪造的可能性较低
    作为图像伪造篡改检测领域的专家，你现在面对一个噪声指纹提取的图像(RdBu_r类型)进行分析，并且知道置信度数值为{truefor_num}。注意，你需要严格以以下格式进行回答：伪造篡改的可能性是什么(较小/有一定可能/较大/非常大)（选取其一，否则不要输出），置信数值达到{truefor_num} ，疑似的修改区域为哪里
    最后要求，输出的全段话不包括下划线和括号
    """
    answer=""
    question=checklen(getText("user",'/home/xinan-works/res/trufor/_local.png',raw))
    main(appid, api_key, api_secret, imageunderstanding_url, question)
    with open ('/home/xinan-works/analyze_res.txt','r') as file:
        data4 = file.read()
    paragraph4_extend = paragraph4+"\n"+"判断的结果是:"+data4

    # lsb
    raw=f"""
    lsb图像通道低位提取结果:对图像颜色通道的低位进行提取成灰度图，一般来说图像比较嘈杂无规律，jpeg格式的图片因为压缩所以会导致一些块状区域的出现，如果像素某些局部的规律性较强，则这部分区域被篡改的可能性较大
    作为图像伪造篡改检测领域的专家，你现在面对一个图像低位通道提取的灰度图进行分析。注意，你需要严格以以下格式进行回答：伪造篡改的可能性____(较小/有一定可能/较大/非常大)选取其一，疑似的修改区域为什么（如果无法给出疑似修改的区域，则不要说出这句话），最多输出100个字
    最后要求，输出的全段话不包括下划线和括号
    """
    answer=""
    question=checklen(getText("user",'/home/xinan-works/res/lsb_result.png',raw))
    main(appid, api_key, api_secret, imageunderstanding_url, question)
    with open ('/home/xinan-works/analyze_res.txt','r') as file:
        data5 = file.read()
    paragraph5_extend = paragraph5+"\n"+"判断的结果是:"+data5

    img_paths = ['/home/xinan-works/res/noise_res.jpg', '/home/xinan-works/res/forgery_result.jpg', '/home/xinan-works/res/ela/difference_scaled.png','/home/xinan-works/res/trufor/_local.png','/home/xinan-works/res/lsb_result.png']  # List of image paths
    output_filename = "complex_layout_example.pdf"
    generate_pdf(output_filename, paragraph1_extend, paragraph2_extend, paragraph3_extend,paragraph4_extend,paragraph5_extend, img_paths)
    print(f"PDF生成完成：{output_filename}")

